#include "Ship.h"
#include <string>
#include "../../common/lib/SDL_rotozoom.h"

#define SHIP_DEFAULT_LIFE 100

void Ship::initUserInfo() {
	int posX = this->parcel->posX;
	int posY = this->parcel->posY;

	this->userInfo = new UserInfo(owner, life, posX, posY, this);
}

void Ship::showOn(SDL_Surface* surface) {
	this->userInfo->updatePosition();
	this->userInfo->showOn(surface);
	WidgetMovimiento::showOn(surface);
}

Ship::Ship(ShipStatus* shipStatus,Widget* parent) :
	WidgetMovimiento(shipStatus->getPosX(), shipStatus->getPosY(), std::string(IMAGES_DEFAULT_FOLDER + shipStatus->getImagePath()
			+ IMAGES_DEFAULT_UNPRESSED), parent) {

	//Informacion basica
	this->imagePath = shipStatus->getImagePath();
	this->rotationVelocity = shipStatus->getVelRotacion();
	this->maximumVelocity = shipStatus->getVelMax();
	this->propulsion = shipStatus->getPropultion();
	this->friction = shipStatus->getFriccion();
	this->bulletLifeTime = shipStatus->getDuracionBala();
	this->angle = shipStatus->getAngle();
	this->owner = shipStatus->getOwner();
	this->life = SHIP_DEFAULT_LIFE;

	loadSurfaceImageFiles();

	nextX = parcel->posX;
	nextY = parcel->posY;

	goingForward = false;
	turningLeft = false;
	turningRight = false;
	shooting = false;
	keyPressed = false;

	velX = 0;
	velY = 0;

	duenoesinstancialocal = false;

	initUserInfo();
}

void Ship::handleEvent(Event event) {

	// Local event in local ship									OR		Remote Event in remote ship
	if ((event.getSender() == this->owner && duenoesinstancialocal) || (event.getSender() == STRING_EMPTY  && !duenoesinstancialocal)) {

		std::stringstream owner;
		owner << "entro al handle del ship ";
		owner << " event key : "<<event.getKey();
		owner << " owner: " << this->owner;

		Logger::log("Ship", "handleEvent",&owner);

		EventType eventType = event.getType();

		//Feo, estoy rompiendo la arquitectura del translator, pero no tengo forma sino.
		//Translate EventType
		if(eventType == UserEvent){
			if (event.getEvent()->user.code == UserKeyPressed) {
				eventType = KeyPressed;
			}else if (event.getEvent()->user.code == UserKeyReleased) {
				eventType = KeyReleased;
			}
		}

		switch (event.getKey()) {
		case KeyUp:
			if (eventType == KeyPressed) {
				goingForward = true;
			} else if (eventType == KeyReleased) {
				goingForward = false;
			}
			keyPressed = false;
			break;
		case KeyLeft:
			if (eventType == KeyPressed) {
				turningLeft = true;
			} else if (eventType == KeyReleased) {
				turningLeft = false;
			}
			keyPressed = false;
			break;
		case KeyRight:
			if (eventType == KeyPressed) {
				turningRight = true;
			} else if (eventType == KeyReleased) {
				turningRight = false;
			}
			keyPressed = false;
			break;
		case Space:
			if ((eventType == KeyPressed) && (keyPressed == false)) {
				shooting = true;
				keyPressed = true;
			} else if ((keyPressed == true) && (eventType == KeyReleased)) {
				keyPressed = false;
				shooting = false;
			}
			break;
		default:
			break;
		}

	}
}

void Ship::resolve() {
	//Timer to get seconds between frames
	if (!timer.is_started()) {
		timer.start();
	}

	float secsPerFrame = (timer.get_ticks() / 1000.0);

	int posX0 = parcel->posX;
	int posY0 = parcel->posY;

	float newVelX = 0;
	float newVelY = 0;
	float deltaX = 0;
	float deltaY = 0;
	nextX = posX0;
	nextY = posY0;

	float degreesPerSec = (1.0 / rotationVelocity) * 360.0;
	float velocity = sqrt(pow(velX, 2.0) + pow(velY, 2.0));
	if (turningLeft)
		angle = ceil((fmod(angle + (degreesPerSec * secsPerFrame), 360.0)));
	else if (turningRight)
		angle = ceil((fmod(angle - (degreesPerSec * secsPerFrame), 360.0)));

	if (angle < 0 )
		angle += 360;
	else if (angle > 360)
		angle -= 360;

	//Verificación si se encuentra yendo hacia adelante
	if (goingForward && velocity < maximumVelocity) {

		float angleInRadians = angle * (M_PI / 180.0);

		float propulsionX = propulsion * cos(angleInRadians);
		float propulsionY = (-1.0) * propulsion * sin(angleInRadians);

		newVelX = velX + propulsionX * secsPerFrame;
		newVelY = velY + propulsionY * secsPerFrame;

		deltaX = fabs(velX * secsPerFrame + (1/2.0) * propulsionX * pow(secsPerFrame, 2.0));
		deltaX = floor(deltaX * 100) / 100;
		deltaX = floor(deltaX + 0.5);
		deltaY = fabs(velY * secsPerFrame + (1/2.0) * propulsionY * pow(secsPerFrame, 2.0));
		deltaY = floor(deltaY * 100) / 100;
		deltaY = floor(deltaY + 0.5);


	} else {

		if(velocity > 0)
		{
			float v1 = velX / velocity;
			float v2 = velY / velocity;
			float u1 = 1.0;
			float u2 = 0.0;

			float angleOposInRadians = acos((u1 * v1 + u2 * v2) / sqrt((pow(u1, 2.0) + pow(u2, 2.0)) * (pow(v1, 2.0) + pow(v2, 2.0))));

			if(velY < 0)
				angleOposInRadians *= (-1.0);

			float frictionX = friction * cos(angleOposInRadians);
			float frictionY = friction * sin(angleOposInRadians);

			newVelX = velX - frictionX * secsPerFrame;
			deltaX = fabs(velX * secsPerFrame + (1/2.0) * frictionX * pow(secsPerFrame, 2.0));
			deltaX = floor(deltaX * 100) / 100;
			deltaX = floor(deltaX + 0.5);

			if ((newVelX < 0 && velX >= 0) || (newVelX >= 0 && velX <= 0))
			{
				newVelX = 0;
				deltaX = 0;
			}

			newVelY = velY - frictionY * secsPerFrame;
			deltaY = fabs(velY * secsPerFrame + (1/2.0) * frictionY * pow(secsPerFrame, 2.0));
			deltaY = floor(deltaY * 100) / 100;
			deltaY = floor(deltaY + 0.5);

			if ((newVelY < 0 && velY >= 0) || (newVelY >= 0 && velY <= 0))
			{
				newVelY = 0;
				deltaY = 0;
			}

		}

	}

	if(velX >= 0)
		nextX = posX0 + deltaX;
	else if(velX < 0)
		nextX = posX0 - deltaX;

	if (velY >= 0)
		nextY = posY0 + deltaY;
	else if (velY < 0)
		nextY = posY0 - deltaY;

	velX = newVelX;
	velY = newVelY;

	if(nextX != 0 || nextY != 0)
	{
		parcel->posX = nextX;
		parcel->posY = nextY;
	}

	//Si hay efecto de combustion se elige la superficie de combustion sino la default
	if (goingForward) {
		this->surface = combustionShipSurface;
	} else
		this->surface = shipSurface;

	//Se inicia controlador de tiempo por frame
	timer.start();
}

void Ship::loadSurfaceImageFiles() {
	shipSurface = SurfaceUtils::loadImage(IMAGES_DEFAULT_FOLDER + imagePath
			+ IMAGES_DEFAULT_UNPRESSED);
	if (shipSurface == NULL) {
		shipSurface = SurfaceUtils::loadImage(SH_DEFAULT_IMAGE);
	}
	//Retrieving combustion image file path
	std::string pathCombustionImage = IMAGES_DEFAULT_FOLDER + imagePath
			+ IMAGES_DEFAULT_PRESSED;
	combustionShipSurface = SurfaceUtils::loadImage(pathCombustionImage);

	//Setting transparent image color
	SDL_SetColorKey(shipSurface, SDL_SRCCOLORKEY, SDL_MapRGB(
			shipSurface->format, 0, 255, 255));

	//Setting transparent image color
	SDL_SetColorKey(combustionShipSurface, SDL_SRCCOLORKEY, SDL_MapRGB(
			combustionShipSurface->format, 0, 255, 255));

	surface = shipSurface;
}

int Ship::getBulletAngle() {
	return angle;
}

bool Ship::isShooting() {
	bool result = this->shooting;
	this->shooting = false;
	return result;
}

int Ship::getBulletLifeTime() {
	return bulletLifeTime;
}

Ship::~Ship() {
	delete userInfo;

	if(surface == shipSurface){
		if(combustionShipSurface != NULL){
			SDL_FreeSurface(combustionShipSurface);
		}
	}else{
		if(shipSurface != NULL){
			SDL_FreeSurface(shipSurface);
		}
	}

	timer.stop();
}

int Ship::getBulletX() {
	float angleInRadians = angle * (M_PI / 180.0);
	return parcel->posX + (sqrt(pow(parcel->width, 2.0) + pow(parcel->height, 2.0)) / 2) * cos(angleInRadians);
}

int Ship::getBulletY() {
	float angleInRadians = angle * (M_PI / 180.0);
	return parcel->posY - (sqrt(pow(parcel->width, 2.0) + pow(parcel->height, 2.0)) / 2) * sin(angleInRadians);
}

std::string Ship::getOwner() {
	return owner;
}

ShipStatus Ship::getShipStatus() {
	Parcel* parcelAux = new Parcel();
	getPosition(parcelAux);

	return ShipStatus(owner, imagePath, rotationVelocity, maximumVelocity,
			propulsion, friction, bulletLifeTime,angle, parcelAux->posX,parcelAux->posY);
}

void Ship::updateStatus(ShipStatus* toUse){
	this->angle = toUse->getAngle();
	delete this->parcel;
	initParcel(toUse->getPosX(),toUse->getPosY());
}
